import React, {
  useEffect,
  useLayoutEffect,
  useState,
  useCallback,
  useMemo,
  useDebugValue,
} from 'react';
const debug = require('debug')('lifecycle');

import styles from './effect.css';

function rand() {
  return Math.ceil(Math.random() * 2);
}

function useMyHook() {
  const c = count;
  const [v, set] = useState(0);
  const doubled = useMemo(() => {
    debug('useMemo: computed double recalc %d', c);
    return 2 * v;
  }, [v]);
  const setRandom = useCallback(() => set(rand()), []);
  useDebugValue(`v=${v}`);
  return { v, doubled, setRandom };
}

function useMyHook2() {
  const c = count;
  useEffect(() => {
    debug('useEffect %d', c);
    return () => {
      debug('useEffect- %d', c);
    }
  });
  useLayoutEffect(() => {
    debug('useLayoutEffect %d', c);
    return () => {
      debug('useLayoutEffect- %d', c);
    }
  });
  useEffect(() => {
    debug('useEffect2 %d', c);
    return () => {
      debug('useEffect2- %d', c);
    }
  });
  useLayoutEffect(() => {
    debug('useLayoutEffect2 %d', c);
    return () => {
      debug('useLayoutEffect2- %d', c);
    }
  });
  useDebugValue(`effects/layoutEffects`);
}

let count = 0;

/**
 * dom 生成前直接在 FC return 前执行即可
 * dom 渲染完成，同步执行 useLayoutEffect, 延迟执行 useEffect
 * dom 事件回调，可以统一使用 useCallback 包裹，增强性能
 * 而所有的计算值，都使用 useMemo 包裹
 *
 * 执行顺序结果
 * 1. render 同步过程，包括里面的 useMemo
 * 2. dom ref 函数得到执行，也就是 mounted to DOM
 * 3. useLayoutEffect 上一次返回的，然后接着本次
 * 4. promise.resolve().then
 * 5. useEffect 上一次返回的，然后接着本次
 * 6. setTimeout
 * 注：ref 在 useLayoutEffect, useEffect, promise.then, setTimeout 时都可以确保持有 DOM el
 */
export default function TryEffect() {
  count += 1;
  debug('FC begin %d', count);

  Promise.resolve(null).then(() => {
    const c = count;
    debug('promise1 resolved %d', c);
  });

  setTimeout(() => {
    const c = count;
    debug('setTimeout1 %d', c);
  });

  const m = useMyHook();
  useMyHook2();

  const elRef = (el: any) => {
    const c = count;
    debug('dom el mounted %d', c, el);
  };

  Promise.resolve(null).then(() => {
    const c = count;
    debug('promise2 resolved %d', c);
  });

  setTimeout(() => {
    const c = count;
    debug('setTimeout2 %d', c);
  });

  debug('FC returning %d', count);

  return (
    <div className={styles.normal}>
      <h3>{m.v}</h3>
      {m.v > 1
        ? (
          <h1 ref={elRef} onClick={m.setRandom}>
            Page effect {m.v} {m.doubled}
          </h1>
        ) : (
          <h2 ref={elRef} onClick={m.setRandom}>
            Page effect {m.v} {m.doubled}
          </h2>
        )}

    </div>
  );
}
